package com.lightkits.wms.domain.deliveryorder.service.impl;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.lightkits.common.db.entity.BdDeliveryOrderBase;
import com.lightkits.common.db.entity.FndResourceTl;
import com.lightkits.common.db.entity.event.BdEvent;
import com.lightkits.common.db.entity.event.BdEventRecord;
import com.lightkits.framework.common.exception.LightKitsBizException;
import com.lightkits.framework.common.logging.Logger;
import com.lightkits.framework.common.logging.LoggerFactory;
import com.lightkits.framework.common.model.CheckResult;
import com.lightkits.framework.common.model.IResult;
import com.lightkits.framework.common.utility.object.ObjectUtil;
import com.lightkits.framework.common.utility.object.ParseUtil;
import com.lightkits.framework.common.utility.validate.IntegrityValidator;
import com.lightkits.framework.soa.common.pipeline.session.SessionInfo;
import com.lightkits.wms.database.dao.WmsDeliveryOrderBaseMapper;
import com.lightkits.wms.database.model.BdDeliveryTaskModel;
import com.lightkits.wms.domain.deliveryorder.model.DloTrackModel;
import com.lightkits.wms.domain.deliveryorder.model.EventParams;
import com.lightkits.wms.domain.deliveryorder.repo.DeliveryOrderDBService;
import com.lightkits.wms.domain.deliveryorder.service.CreateDeliveryEventDomain;
import com.lightkits.wms.domain.deliveryorder.service.DeliveryExeDomain;
import com.lightkits.wms.domain.deliveryorder.service.doDoubboService;
import com.lightkits.wms.domain.saveonhand.models.OnhandParams;
import com.lightkits.wms.domain.saveonhand.repo.BdEventRecordService;
import com.lightkits.wms.domain.saveonhand.repo.BdEventService;
import com.lightkits.wms.domain.saveonhand.service.UseParamsDomain;
import com.lightkits.wms.dto.deliveryorder.model.DeliveryExeDTO;
import com.lightkits.wms.dto.onhand.model.OnhandDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

/**
 * DeliveryExeDomainImpl
 *
 * @author jing.wei@hand-china.com
 * Created on 2019/2/26 16:11
 */
@Service
public class DeliveryExeDomainImpl implements DeliveryExeDomain {

    private final Logger LOGGER = LoggerFactory.getLogger(DeliveryExeDomainImpl.class);

    private final CreateDeliveryEventDomain createEventDomain;

    private final DeliveryOrderDBService deliveryOrderDBService;

    private final BdEventService bdEventService;

    private final BdEventRecordService bdEventRecordService;

    private final UseParamsDomain useParamsDomain;

    private final WmsDeliveryOrderBaseMapper bdDeliveryOrderBaseMapper;

    private final doDoubboService doDomainService;

    @Autowired
    public DeliveryExeDomainImpl(CreateDeliveryEventDomain createEventDomain, DeliveryOrderDBService deliveryOrderDBService, BdEventService bdEventService, BdEventRecordService bdEventRecordService, UseParamsDomain useParamsDomain, WmsDeliveryOrderBaseMapper bdDeliveryOrderBaseMapper, doDoubboService doDomainService) {
        this.createEventDomain = createEventDomain;
        this.deliveryOrderDBService = deliveryOrderDBService;
        this.bdEventService = bdEventService;
        this.bdEventRecordService = bdEventRecordService;
        this.useParamsDomain = useParamsDomain;
        this.bdDeliveryOrderBaseMapper = bdDeliveryOrderBaseMapper;
        this.doDomainService = doDomainService;
    }

    /**
     * 创建发货单执行参数
     *
     * @param exeDTO 发货单执行参数
     * @return
     */
    private CheckResult<BdDeliveryOrderBase> updateDelivery(DeliveryExeDTO exeDTO) {
        CheckResult<BdDeliveryOrderBase> checkResult = new CheckResult<>();
        checkResult.setSuccessful(true);
        if (ObjectUtil.isEmpty(exeDTO)) {
            checkResult.setMessage("the delivery order is empty");
            checkResult.setSuccessful(false);
            return checkResult;
        }
        IResult result = this.checkParams(exeDTO);
        if (!result.isSuccessful()) {
            result.fill(checkResult);
            return checkResult;
        }
        BdDeliveryOrderBase base = new BdDeliveryOrderBase().selectById(exeDTO.getDeliveryOrderId());
        if (ObjectUtil.isEmpty(base)) {
            checkResult.setMessage("the delivery order Id is invalid");
            checkResult.setSuccessful(false);
            return checkResult;
        }
        base.setStatus("EXECUTED");
        base.setExeWorkerId(ParseUtil.tryLongWithException(exeDTO.getWorkerId()));
        //执行数量小于现有数量时报错
        if (base.getQty() < Integer.valueOf(exeDTO.getExeQty())) {
            return checkResult.fail("the Execute Quantity s greater than MakeOrder Quantity");
        }
        //发货单上执行数量进行累加
        if (!ObjectUtil.isEmpty(base.getExeQty())) {
            base.setExeQty(base.getExeQty() + ParseUtil.tryLongWithException(exeDTO.getExeQty()));
        } else {
            base.setExeQty(ParseUtil.tryLongWithException(exeDTO.getExeQty()));
        }

        base.setRemark(exeDTO.getRemark());
        List<BdEvent> events = new ArrayList<>();
        CheckResult<BdEvent> event = this.convertEvent(exeDTO);
        if (!event.isSuccessful() || ObjectUtil.isEmpty(event.getData())) {
            event.fill(checkResult);
            return checkResult;
        }
        events.add(event.getData());
        base.store(events);
        checkResult.setData(base);
        return checkResult;
    }

    /**
     * 发货执行参数创建
     *
     * @param dto 发货执行参数
     * @return
     */
    private CheckResult<BdEvent> convertEvent(DeliveryExeDTO dto) {
        EventParams params = new EventParams();
        params.setEventTypeCode("DELIVERY_ORDER_EXE");
        params.setKeyValue("EXECUTED");
        params.setObjectId(ParseUtil.tryLongWithException(dto.getDeliveryOrderId()));
        params.setObjectType("DELIVERY_ORDER");
        params.setWorkerId(dto.getWorkerId());
        params.setRecordType("STATUS");
        params.setParentEventId(dto.getParentEventId());
        return createEventDomain.createEvent(params);

    }

    /**
     * 发货执行参数校验
     *
     * @param exeDTO 发货执行参数
     * @return
     */
    private IResult checkParams(DeliveryExeDTO exeDTO) {
        try {
            IntegrityValidator.begin().validate(exeDTO.getDeliveryOrderId(), "Delivery Order Id")
                    .validate(exeDTO.getExeQty(), " Execute Quantity")
                    .validate(exeDTO.getWorkerId(), "Worker Id");
            Pattern pattern = Pattern.compile("^([0-9]{1,})$");
            if (!pattern.matcher(exeDTO.getExeQty()).matches()) {
                return IResult.fail("The Quantity is invalid");
            }
        } catch (LightKitsBizException e) {
            return e.result();
        }
        return IResult.success();
    }

    /**
     * 发货执行
     *
     * @param exeDTO 发货执行参数
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public IResult insertValue(DeliveryExeDTO exeDTO) {
        //创建发货单
        CheckResult<BdDeliveryOrderBase> result = this.updateDelivery(exeDTO);
        if (!result.isSuccessful() || ObjectUtil.isEmpty(result.getData())) {
            throw new LightKitsBizException(result.getMessage());
        }
        BdDeliveryOrderBase orderBase = result.getData();
        //修改发货单
        boolean createDEliveryFlag = deliveryOrderDBService.updateById(result.getData());
        if (!createDEliveryFlag) {
            throw new LightKitsBizException("Execute Delivery Order error.");
        }
        //创建发后执行事件
        List<BdEvent> eventBase = new ArrayList<>();
        List<BdEventRecord> eventRecordBase = new ArrayList<>();

        List<Object> events = orderBase.take();
        for (Object object : events) {
            if (object.getClass().equals(BdEvent.class)) {
                BdEvent event = (BdEvent) object;
                eventBase.add(event);
            }
        }
        boolean insertEventFlag = bdEventService.insertBatch(eventBase);
        if (!insertEventFlag) {
            throw new LightKitsBizException("Save  events of Execute Delivery Order error.");
        }

        //创建发货执行快照
        for (BdEvent event : eventBase) {
            List<Object> records = event.take();
            for (Object object : records) {
                if (object.getClass().equals(BdEventRecord.class)) {
                    BdEventRecord record = (BdEventRecord) object;
                    record.setEventId(event.getId());
                    eventRecordBase.add(record);
                }
            }
        }

        boolean insertRecordsFlag = bdEventRecordService.insertBatch(eventRecordBase);
        if (!insertRecordsFlag) {
            throw new LightKitsBizException("Save eventRecords of Execute Delivery Order  error.");
        }
       //创建现有量参数
        OnhandDTO dto = convertParams(orderBase, exeDTO);
        try {
            if (dto != null) {
                //减少现有量
                CheckResult<String> checkResultRes = new CheckResult<>();
                checkResultRes.setSuccessful(true);
                CheckResult<OnhandParams> checkResult = useParamsDomain.getOnhandParams(dto);
                if(!checkResult.isSuccessful()||checkResult.getData()==null){
                    throw new LightKitsBizException(checkResult.getMessage());
                }
                IResult onhandResult = useParamsDomain.insertValue(checkResult.getData());
                if (!onhandResult.isSuccessful()) {
                    throw new Exception(onhandResult.getMessage());
                }
            }


        } catch (Exception e) {
            LOGGER.error("SaveOnhandExecutor.error", e);
            throw new LightKitsBizException(e);
        }

        //创建需求订单的跟踪
        DloTrackModel model = convertTrack(orderBase, exeDTO);
        IResult trackResult = doDomainService.createTrack(model);
        if (!trackResult.isSuccessful()) {
            return trackResult;
        }
        //根据是否完全发货（满足需求订单中的需求数量改变需求订单的状态）
        List<BdDeliveryTaskModel> taskModel = bdDeliveryOrderBaseMapper.queryDeliveryTaskByDoNum(orderBase.getDemandId().toString(), SessionInfo.languageCode());
        if (!ObjectUtil.isNullOrEmpty(taskModel) && taskModel.size() > 1) {
            return IResult.fail("update do is error");
        }

        if (new BigDecimal(taskModel.get(0).getDemandQty()).compareTo(new BigDecimal(taskModel.get(0).getDeliveryQty())) <= 0) {
            IResult updateSopResult = doDomainService.updDoStatus(orderBase.getDemandId(), "FINISHED", orderBase.getCreateWorkerId().toString());

            if (!updateSopResult.isSuccessful()) {
                return updateSopResult;
            }
        }
        return IResult.success();
    }

    /**
     * 创建现有量参数
     *
     * @param dto    发货单
     * @param exeDTO 发货执行参数
     * @return
     */
    private OnhandDTO convertParams(BdDeliveryOrderBase dto, DeliveryExeDTO exeDTO) {
        OnhandDTO params = new OnhandDTO();
        try {
            params.setEventTypeCode("FP_ACCESS_STORAGE");
            params.setChangeDirection("OUT");
            params.setChangeQuantity(exeDTO.getExeQty());
            params.setItemId(dto.getItemId().toString());
            params.setOrgId(dto.getOrganizationId().toString());
            params.setRemark(dto.getRemark());
            params.setUomCode(dto.getUom());
            params.setWarehouseId(exeDTO.getWarehouseId());
            params.setOwnerType("OWN");
        } catch (Exception e) {
            LOGGER.error("convertParams.error", e);
            throw new LightKitsBizException(e);
        }
        return params;
    }

    /**
     * 创建需求订单跟踪参数
     *
     * @param dto    发货单
     * @param exeDTO 发货执行参数
     * @return
     */
    private DloTrackModel convertTrack(BdDeliveryOrderBase dto, DeliveryExeDTO exeDTO) {
        DloTrackModel model = new DloTrackModel();
        try {
            model.setDemandId(dto.getDemandId().toString());
            model.setKeyValue(exeDTO.getExeQty());
            model.setWorkerId(exeDTO.getWorkerId());
            model.setOrgId(dto.getOrganizationId().toString());
            FndResourceTl resourceTl = new FndResourceTl().selectOne(new EntityWrapper().eq(FndResourceTl.RESOURCE_ID, model.getWorkerId()));
            if (!ObjectUtil.isEmpty(resourceTl)) {
                model.setWorkerName(resourceTl.getResourceName());
            }

        } catch (Exception e) {
            LOGGER.error("convertTrack.error", e);
            throw new LightKitsBizException(e);
        }
        return model;
    }
}
